#include "s_st7789v_user.h"
#include "s_st7789v.h"

#include "h_stm32_hal_defines.h"

#include "h_stm32_hal_timer.h"

#include "FreeRTOS.h"
#define st7789v_malloc        pvPortMalloc
#define st7789v_free          vPortFree

//////////////////////////////////////////////////////////////////////////////////
#define S_ST7789V_CTL_PORT                        B
#define S_ST7789V_DATA_PORT                       C

#define S_ST7789V_RS_PORT                         S_ST7789V_CTL_PORT
#define S_ST7789V_RS_PIN                          0

#define S_ST7789V_CS_PORT                         S_ST7789V_CTL_PORT
#define S_ST7789V_CS_PIN                          1

#define S_ST7789V_RD_PORT                         S_ST7789V_CTL_PORT
#define S_ST7789V_RD_PIN                          2

#define S_ST7789V_WR_PORT                         S_ST7789V_CTL_PORT
#define S_ST7789V_WR_PIN                          3

#define S_ST7789V_RST_PORT                        S_ST7789V_CTL_PORT
#define S_ST7789V_RST_PIN                         4

#define S_ST7789V_BL_PORT                         S_ST7789V_CTL_PORT
#define S_ST7789V_BL_PIN                          5
//////////////////////////////////////////////////////////////////////////////////
static s_st7789v_t s_st7789v;

// static unsigned int draw_x_now = 0, draw_y_now = 0;
// static unsigned int start_x = 0, start_y = 0, end_x = 0, end_y = 0;

forbidden_pixel f_p_t;

static void s_st7789v_user_data_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOC_CLK_ENABLE();

    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_DATA_PORT), STM32HAL_GPIO_Pin(0) | \
        STM32HAL_GPIO_Pin(1) | STM32HAL_GPIO_Pin(2) | STM32HAL_GPIO_Pin(3) | \
        STM32HAL_GPIO_Pin(4) | STM32HAL_GPIO_Pin(5) | STM32HAL_GPIO_Pin(6) | \
        STM32HAL_GPIO_Pin(7) | STM32HAL_GPIO_Pin(8) | STM32HAL_GPIO_Pin(9) | \
        STM32HAL_GPIO_Pin(10) | STM32HAL_GPIO_Pin(11) | STM32HAL_GPIO_Pin(12) | \
        STM32HAL_GPIO_Pin(13) | STM32HAL_GPIO_Pin(14) | STM32HAL_GPIO_Pin(15), \
        GPIO_PIN_RESET);

    GPIO_InitStruct.Pin = STM32HAL_GPIO_Pin(0) | \
        STM32HAL_GPIO_Pin(1) | STM32HAL_GPIO_Pin(2) | STM32HAL_GPIO_Pin(3) | \
        STM32HAL_GPIO_Pin(4) | STM32HAL_GPIO_Pin(5) | STM32HAL_GPIO_Pin(6) | \
        STM32HAL_GPIO_Pin(7) | STM32HAL_GPIO_Pin(8) | STM32HAL_GPIO_Pin(9) | \
        STM32HAL_GPIO_Pin(10) | STM32HAL_GPIO_Pin(11) | STM32HAL_GPIO_Pin(12) | \
        STM32HAL_GPIO_Pin(13) | STM32HAL_GPIO_Pin(14) | STM32HAL_GPIO_Pin(15);

    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(STM32HAL_GPIO_Port(S_ST7789V_DATA_PORT), &GPIO_InitStruct);
}

static void s_st7789v_user_control_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();
    // RS
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_RS_PORT), STM32HAL_GPIO_Pin(S_ST7789V_RS_PIN), GPIO_PIN_RESET);
    GPIO_InitStruct.Pin = STM32HAL_GPIO_Pin(S_ST7789V_RS_PIN);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(STM32HAL_GPIO_Port(S_ST7789V_RS_PORT), &GPIO_InitStruct);

    // CS
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_CS_PORT), STM32HAL_GPIO_Pin(S_ST7789V_CS_PIN), GPIO_PIN_RESET);
    GPIO_InitStruct.Pin = STM32HAL_GPIO_Pin(S_ST7789V_CS_PIN);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(STM32HAL_GPIO_Port(S_ST7789V_CS_PORT), &GPIO_InitStruct);

    // RD
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_RD_PORT), STM32HAL_GPIO_Pin(S_ST7789V_RD_PIN), GPIO_PIN_RESET);
    GPIO_InitStruct.Pin = STM32HAL_GPIO_Pin(S_ST7789V_RD_PIN);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(STM32HAL_GPIO_Port(S_ST7789V_RD_PORT), &GPIO_InitStruct);

    // WR
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_WR_PORT), STM32HAL_GPIO_Pin(S_ST7789V_WR_PIN), GPIO_PIN_RESET);
    GPIO_InitStruct.Pin = STM32HAL_GPIO_Pin(S_ST7789V_WR_PIN);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(STM32HAL_GPIO_Port(S_ST7789V_WR_PORT), &GPIO_InitStruct);

    // RST
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_RST_PORT), STM32HAL_GPIO_Pin(S_ST7789V_RST_PIN), GPIO_PIN_RESET);
    GPIO_InitStruct.Pin = STM32HAL_GPIO_Pin(S_ST7789V_RST_PIN);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(STM32HAL_GPIO_Port(S_ST7789V_RST_PORT), &GPIO_InitStruct);

    // BL
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_BL_PORT), STM32HAL_GPIO_Pin(S_ST7789V_BL_PIN), GPIO_PIN_RESET);
    GPIO_InitStruct.Pin = STM32HAL_GPIO_Pin(S_ST7789V_BL_PIN);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(STM32HAL_GPIO_Port(S_ST7789V_BL_PORT), &GPIO_InitStruct);
}

static void s_st7789v_user_rs_set(s_st7789v_gpio_status level)
{
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_RS_PORT), STM32HAL_GPIO_Pin(S_ST7789V_RS_PIN), level);
}

static void s_st7789v_user_cs_set(s_st7789v_gpio_status level)
{
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_CS_PORT), STM32HAL_GPIO_Pin(S_ST7789V_CS_PIN), level);
}

static void s_st7789v_user_rd_set(s_st7789v_gpio_status level)
{
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_RD_PORT), STM32HAL_GPIO_Pin(S_ST7789V_RD_PIN), level);
}

static void s_st7789v_user_wr_set(s_st7789v_gpio_status level)
{
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_WR_PORT), STM32HAL_GPIO_Pin(S_ST7789V_WR_PIN), level);
}

static void s_st7789v_user_rst_set(s_st7789v_gpio_status level)
{
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_RST_PORT), STM32HAL_GPIO_Pin(S_ST7789V_RST_PIN), level);
}

static void s_st7789v_user_bl_set(s_st7789v_gpio_status level)
{
    HAL_GPIO_WritePin(STM32HAL_GPIO_Port(S_ST7789V_BL_PORT), STM32HAL_GPIO_Pin(S_ST7789V_BL_PIN), level);
}

static void s_st7789v_user_write_u16(unsigned short data)
{
    STM32HAL_GPIO_Port(S_ST7789V_DATA_PORT)->ODR = (unsigned short)data;
}

void s_st7789v_user_init(void)
{
    s_st7789v_user_data_gpio_init();
    s_st7789v_user_control_gpio_init();

    s_st7789v.set_rs = &s_st7789v_user_rs_set;
    s_st7789v.set_cs = &s_st7789v_user_cs_set;
    s_st7789v.set_rd = &s_st7789v_user_rd_set;
    s_st7789v.set_wr = &s_st7789v_user_wr_set;
    s_st7789v.set_rst = &s_st7789v_user_rst_set;
    s_st7789v.set_bl = &s_st7789v_user_bl_set;
    s_st7789v.delay = &delay_ms;
    s_st7789v.write_u16 = &s_st7789v_user_write_u16;

    s_st7789v_init(&s_st7789v);
}

void s_st7789v_user_set_pixel_arear(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
{
    s_st7789v_set_column_row_addr(&s_st7789v, x1, x2, y1, y2);
}

signed char s_st7789v_user_set_pixel_add_forbiden_area(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
{
    forbidden_pixel *fp = &f_p_t;
    forbidden_pixel *fp_add;
    while(fp->next != NULL)
    {
        fp = fp->next;
        if(fp->sx == x1 && fp->sy == y1 && fp->ex == x2 && fp->ey == y2)
        {
            printf("already added\r\n");
            return (1);
        }

        
    }

    fp_add = (forbidden_pixel *)st7789v_malloc(sizeof(forbidden_pixel));
    if(fp_add == NULL)
    {
        printf("add malloc failed\r\n");
        return (-1);
    }

    fp_add->sx = x1;
    fp_add->sy = y1;
    fp_add->ex = x2;
    fp_add->ey = y2;

    fp_add->next = NULL;

    fp->next = fp_add;

    printf("add success\r\n");

    return 0;

}

signed char s_st7789v_user_set_pixel_del_forbiden_area(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
{
    forbidden_pixel *fp = &f_p_t;
    forbidden_pixel *fp_del;

    while(fp->next != NULL)
    {
        if(fp->next->sx == x1 && fp->next->sy == y1 && fp->next->ex == x2 && fp->next->ey == y2)
        {
            printf("del found\r\n");
            break;
        }
        fp = fp->next;
    }

    // Not found
    if(fp->next == NULL)
    {
        printf("del not found\r\n");
        return (-1);
    }

    fp_del = fp->next;
    fp->next = fp_del->next;
    st7789v_free(fp_del);
    fp_del = NULL;

    printf("del success\r\n");

    return 0;
}

static void s_st7789v_user_set_pixel_get_new_arear(forbidden_pixel *fp, \
                                                unsigned short *x1, unsigned short *y1, \
                                                unsigned short *x2, unsigned short *y2)
{
    unsigned short new_x1, new_x2, new_y1, new_y2;

    if((*x2 <= fp->sx) || (*x1 >= fp->ex) || (*y2 <= fp->sy) || (*y1 >= fp->ey)) // Out of the forbidden filter area
    {
        return;
    }
    else
    {
        if(*x1 <= fp->sx && *x2 >= fp->ex)
        {
            new_x1 = *x1;
            new_x2 = *x2;
        }
        else if(*x1 <= fp->sx && *x2 >= fp->sx)
        {
            new_x1 = *x1;
            new_x2 = fp->sx - 1;
        }
        else if(*x1 <= fp->ex && *x2 >= fp->ex)
        {
            new_x1 = fp->ex + 1;
            new_x2 = *x2;
        }
        else // Inner
        {
            new_x1 = 0;
            new_x2 = 0;
        }

        if(new_x1 == 0 && new_x2 == 0)
        {
            if(*y1 <= fp->sy && *y2 >= fp->ey)
            {
                new_y1 = *y1;
                new_y2 = *y2;
            }
            else if(*y1 <= fp->sy && *y2 >= fp->sy)
            {
                new_y1 = *y1;
                new_y2 = fp->sy - 1;
            }
            else if(*y1 <= fp->ey && *y2 >= fp->ey)
            {
                new_y1 = fp->ey;
                new_y2 = *y2;
            }
            else // Inner
            {
                new_y1 = 0;
                new_y2 = 0;
            }
        }
        else
        {
            new_y1 = *y1;
            new_y2 = *y2;
        }
    }

    *x1 = new_x1;
    *x2 = new_x2;
    *y1 = new_y1;
    *y2 = new_y2;
}

void s_st7789v_user_set_pixel_arear_with_check(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
{
    // if(f_p_t.sx < f_p_t.ex && f_p_t.sy < f_p_t.ey) // Enable
    // {
        
        

    //     s_st7789v_set_column_row_addr(&s_st7789v, new_x1, new_x2, new_y1, new_y2);

    // }
    // else
    // {
    //     s_st7789v_set_column_row_addr(&s_st7789v, x1, x2, y1, y2);
    // }

    forbidden_pixel *fp = f_p_t.next;
    while(fp != NULL)
    {
        s_st7789v_user_set_pixel_get_new_arear(fp, &x1, &y1, &x2, &y2);
        fp = fp->next;
    }

    s_st7789v_set_column_row_addr(&s_st7789v, x1, x2, y1, y2);
}

void s_st7789v_user_start_set_pixel(void)
{
    s_st7789v_send_cmd(&s_st7789v, 0x2C);
}

void s_st7789v_user_start_read_pixel(void)
{
    s_st7789v_send_cmd(&s_st7789v, 0x2E);
}

void s_st7789v_user_set_pixel(unsigned short color)
{
    s_st7789v_send_data(&s_st7789v, color);

    // draw_x_now ++;
    // if(draw_x_now > end_x)
    // {
    //     draw_x_now = start_x;
    //     draw_y_now++;
    // }
}

void s_st7789v_user_set_pixel_with_check(unsigned short xnow, unsigned short ynow, unsigned short color)
{
    forbidden_pixel *fp = f_p_t.next;
    while(fp != NULL)
    {
        if(xnow >= fp->sx && xnow <= fp->ex && ynow >= fp->sy && ynow <= fp->ey)
        {
            s_st7789v_user_start_read_pixel();
            s_st7789v_send_data(&s_st7789v, color);
            s_st7789v_user_start_set_pixel();
            return;
        }
        fp = fp->next;
    }
    

    s_st7789v_send_data(&s_st7789v, color);

}

void s_st7789v_user_fillall(unsigned short width, unsigned short height, unsigned short color)
{
    s_st7789v_fillall(&s_st7789v, width, height, color);
}